package com.bonc.ioc.demo.aop;

import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.bonc.ioc.common.util.AppReply;
import com.bonc.ioc.demo.exception.McpException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * * @description feign接口 一些公用逻辑 切片 实现类 详细逻辑参考FeignExceptionCheck注解
 *
 * @author jin.xu
 * @date 2020/12/2 10:47
 * @change: 2020/12/2 10:47 by jin.xu for init
 */
@Aspect
@Component
public class FeignExceptionCheckAspect {
    @Autowired
    private NacosDiscoveryProperties discoveryProperties;

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Pointcut("@annotation(com.bonc.ioc.demo.aop.FeignExceptionCheck)")
    public void controllerInteceptor() {
    }

    @Around("controllerInteceptor()")
    public Object before(ProceedingJoinPoint pjp) throws Throwable {
        //获取被注解的方法
        MethodInvocationProceedingJoinPoint mjp = (MethodInvocationProceedingJoinPoint) pjp;
        MethodSignature signature = (MethodSignature) mjp.getSignature();
        Method method = signature.getMethod();
        FeignExceptionCheck feignExceptionCheck = method.getAnnotation(FeignExceptionCheck.class);

        if (feignExceptionCheck.checkServiceName()) {
            String serviceName = null;

            try {
                FeignClient feignClient = method.getDeclaringClass().getAnnotation(FeignClient.class);
                serviceName = feignClient.value();
            } catch (Exception ex) {
                // 此处可能没找到对应的服务名 不启用校验逻辑 直接返回
                return pjp.proceed();
            }

            // 拿到服务发现的相关API
            NamingService namingService = discoveryProperties.namingServiceInstance();

            if (namingService != null) {
                try {
                    // 获取 nacos client
                    Instance instance = namingService.selectOneHealthyInstance(serviceName);

                    if (instance == null) {
                        throw new McpException(serviceName + "服务未启动");
                    }
                } catch (IllegalStateException ex1) {
                    throw new McpException(serviceName + "服务未启动");
                }
            }
        }

        return pjp.proceed();
    }

    @AfterReturning(pointcut = "controllerInteceptor()", returning = "object")
    public Object afterReturning(JoinPoint joinPoint, Object object) throws Throwable {
        //获取被注解的方法
        MethodInvocationProceedingJoinPoint mjp = (MethodInvocationProceedingJoinPoint) joinPoint;
        MethodSignature signature = (MethodSignature) mjp.getSignature();
        Method method = signature.getMethod();
        FeignExceptionCheck feignExceptionCheck = method.getAnnotation(FeignExceptionCheck.class);

        if (feignExceptionCheck.throwExceptionByAppReply()) {
            if (object instanceof AppReply) {
                AppReply appReply = (AppReply) object;

                if (!AppReply.SUCCESS_CODE.equals(appReply.getCode())) {
                    throw new McpException(appReply.getMsg(),appReply.getCode());
                }
            }
        }

        return object;
    }
}
